/*
 * SpeechEnhancement
 * author ydwang3
 * create at 2017/8/21 20:05
 * CopyRight IFLYTEK Co.,Ltd. All Rights Reserved.
 */
package com.iflytek.speech.semix;

import android.util.Log;
import com.iflytek.speech.NativeHandle;
import com.iflytek.speech.libissse;
import java.util.concurrent.CopyOnWriteArrayList;

public enum SeManager {
    I;

    private BEAM beam = BEAM.UNSPECIFIED;

    private final String TAG = SeManager.class.getSimpleName();

    private final NativeHandle HANDLER = new NativeHandle();

    private final CopyOnWriteArrayList<IBeamChange> BEAM_CHANGE_LISTENERS = new CopyOnWriteArrayList<>();
    private static boolean isMaeMode = false;
    //se是否初始化完成的标志位
    private boolean isSeCreated = true;

    SeManager() {
        Log.i(TAG, "Constructor " + TAG);
    }

    public String currentSeMode;

    /**
     * 初始化
     * @param mode
     * @param resPath
     * @return
     */
    public int init(ENV_MODE mode,String resPath) {
        //创建se实例
        int ret = libissse.create(HANDLER, resPath);
        Log.d(TAG, "init: "+ret);
        if(0 == ret) {
            switch (mode) {
                case PURE_SOFT:
                    //纯软版本下设置MAB模式
                    currentSeMode =   libissse.ISS_SE_PARAM_VALUE_MAB_MODE;
                    libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                            libissse.ISS_SE_PARAM_VALUE_MAB_MODE);
                    isMaeMode = false;
                    break;
                case HARD_SOFT:
                    //硬件+软版本下设置VAD ONLy模式
                    libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                            libissse.ISS_SE_PARAM_VALUE_VAD_ONLY_MODE);
                    break;
                case SINGLEMAE_SOFT:
                    libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                            libissse.ISS_SE_PARAM_VALUE_LSA_MODE);
                    break;
            }
        }
        return ret;
    }

    /**
     * 切换为mab模式
     * @return
     */
    public synchronized int changeToMab() {
        if(!isMaeMode()){
            Log.d(TAG,"the mode is mab");
            return 0;
        }
        int ret = -1;
        isSeCreated = false;
        int isreset = reset();
        Log.d(TAG,"isreset: "+isreset);
        if(isreset == 0) {
            ret = libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                    libissse.ISS_SE_PARAM_VALUE_MAB_MODE);
            Log.d(TAG, "change to mab:" + ret);
            if (ret == 0) {
                isMaeMode = false;
            }
            currentSeMode = libissse.ISS_SE_PARAM_VALUE_MAB_MODE;
            isSeCreated = true;
            setBeanIndex(this.beam);
        }
        return ret;
    }

    /**
     * 切换为mae模式
     * @return
     */
    public synchronized int changeToMae() {
        if(isMaeMode()){
            Log.d(TAG,"the mode is mae");
            return 0;
        }
        int ret = -1;
        isSeCreated = false;
        int isreset = reset();
        Log.d(TAG,"isreset: "+isreset);
        if(isreset == 0) {
            ret = libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                    libissse.ISS_SE_PARAM_VALUE_MAE_MODE);
            Log.d(TAG, "change to mae:" + ret);
            if (ret == 0) {
                isMaeMode = true;
            }
            currentSeMode = libissse.ISS_SE_PARAM_VALUE_MAE_MODE;
            isSeCreated = true;

        }
        return ret;
    }

    public static boolean isMaeMode() {
        return isMaeMode;
    }

    /**
     * 切换为mae and mae 模式
     * @return
     */
    public int changeToMaeAndMab() {
        int ret = 0;
        if (!libissse.ISS_SE_PARAM_VALUE_MAB_AND_MAE_MODE.equals(currentSeMode)) {
            isSeCreated = false;
            int isreset = reset();
            Log.d(TAG,"isreset: "+isreset);
            ret = libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                    libissse.ISS_SE_PARAM_VALUE_MAB_AND_MAE_MODE);
            currentSeMode = libissse.ISS_SE_PARAM_VALUE_MAB_AND_MAE_MODE;
        }
        isSeCreated = true;
        Log.d(TAG, "changeToMaeAndMab:" + ret);
        return ret;
    }

    /**
     * 切花为快速mae模式(一般是点击按键)
     * @return
     */
    public int changeToFakeMae() {
        int ret = 0;
        if(!libissse.ISS_SE_PARAM_VALUE_FAKE_MAE_MODE.equals(currentSeMode)){
            isSeCreated = false;
            int isreset = reset();
            Log.d(TAG,"isreset: "+isreset);
            ret = libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                    libissse.ISS_SE_PARAM_VALUE_FAKE_MAE_MODE);
            currentSeMode = libissse.ISS_SE_PARAM_VALUE_FAKE_MAE_MODE;
        }
        isSeCreated = true;
        Log.d(TAG, "change to fake mae:" + ret);
        return ret;
    }

    /**
     * 切换为 vad only模式
     * @return
     */
    public int changeToMabVadOnly() {
        int ret = 0;
        if(!libissse.ISS_SE_PARAM_VALUE_VAD_ONLY_MODE.equals(currentSeMode)){
            isSeCreated = false;
            int isreset = reset();
            Log.d(TAG,"isreset: "+isreset);
            ret = libissse.setParam(HANDLER, libissse.ISS_SE_PARAM_WORK_MODE,
                    libissse.ISS_SE_PARAM_VALUE_VAD_ONLY_MODE);
            currentSeMode = libissse.ISS_SE_PARAM_VALUE_VAD_ONLY_MODE;
        }
        isSeCreated = true;
        Log.d(TAG, "change to mabvadonly:" + ret);
        setBeanIndex(this.beam);
        return ret;
    }

    /**
     * 销毁实例
     * @return
     */
    public synchronized int destroy() {
        return libissse.destroy(HANDLER);
    }

    /**
     * 重置实例
     * @return
     */
    public synchronized int reset() {
        return libissse.reset(HANDLER);
    }

    /**
     * 输入音频
     * @param quadRecordBuffer
     * @param quadRecordBufferOut
     * @param outChannels
     * @return
     */
    public synchronized int process(byte[] quadRecordBuffer, byte[] quadRecordBufferOut, int[] outChannels) {
        if(!isSeCreated){
            return -1;
        }
        return libissse.process(HANDLER, quadRecordBuffer, libissse.ISS_SE_FRAME_SHIFT,
                quadRecordBufferOut, outChannels);
    }

    public BEAM getBeam() {
        return beam;
    }

    /**
     * 设置波束方向
     * @param beam
     * @return
     */
    public int setBeanIndex(BEAM beam) {
        Log.i(TAG, "setBeanIndex:" + beam);
        if (!this.beam.equals(beam)) {
            for (IBeamChange beamChange : BEAM_CHANGE_LISTENERS) {
                if (null != beamChange) {
                    beamChange.onBeamChange(beam);
                }
            }
        }

        int ret = 0;
        this.beam = beam;
        switch (beam) {
            case LEFT:
                ret = setParam(libissse.ISS_SE_PARAM_BEAM_INDEX, libissse.ISS_SE_PARAM_BEAM_INDEX_VALUE_FRONT_LEFT);
                Log.d(TAG, "setBeanIndex left ret:" + ret);
                return ret;
            case RIGHT:
                ret = setParam(libissse.ISS_SE_PARAM_BEAM_INDEX, libissse.ISS_SE_PARAM_BEAM_INDEX_VALUE_FRONT_RIGTH);
                Log.d(TAG, "setBeanIndex right ret:" + ret);
                return ret;
            case UNSPECIFIED:
//                ret = setParam(libissse.ISS_SE_PARAM_BEAM_INDEX, libissseopt.ISS_SEOPT_PARAM_BEAM_INDEX_VALUE_INIT);
                Log.d(TAG, "setBeanIndex UNSPECIFIED ret:" + ret);
                return ret;
        }
        throw new IllegalArgumentException("Invalid beam." + beam);
    }

    private int setParam(String key, String value) {
        return libissse.setParam(HANDLER, key, value);
    }

    public void addOnBeamChangeListener(IBeamChange listener) {
        BEAM_CHANGE_LISTENERS.add(listener);
    }

    public void removeOnBeamChangeListener(IBeamChange listener) {
        BEAM_CHANGE_LISTENERS.remove(listener);
    }



    /**
     * 波束
     */
    public enum BEAM {
        LEFT("left"),
        RIGHT("right"),
        UNSPECIFIED("all");

        public final String s;

        BEAM(String s) {
            this.s = s;
        }
    }

    /**
     * 工作模式，纯软or硬件模块2.0+软件方案
     */
    public enum ENV_MODE {
        PURE_SOFT,
        HARD_SOFT,
        SINGLEMAE_SOFT
    }

    public interface IBeamChange {
        void onBeamChange(BEAM beam);
    }
}
